package cn.gotom.svg;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.HashMap;

import org.apache.log4j.Logger;
import org.xml.sax.InputSource;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PictureDrawable;

/**
 * @author 裴绍国
 * @author <a href="mailto:peixere@gmail.com">裴绍国</a>
 */
public class SVGDiagram implements SVG
{
	public static final long serialVersionUID = 0;

	protected final Logger log = Logger.getLogger(this.getClass());
	private RectF deviceViewport = new RectF(0, 0, 480, 800);
	private Canvas canvas;
	private String backgroundColor = "#FFFFFF";
	private boolean debug = false;
	private int width;
	private int height;
	private SVGRoot root;
	private final Picture picture = new Picture();
	private final Paint paint = new Paint();
	private final HashMap<String, SVGElement> idMap = new HashMap<String, SVGElement>();

	public void render(Canvas canvas)
	{
		this.canvas = canvas;
		this.render();
	}

	private void render()
	{
		height = width = 102400;
		if (canvas == null)
		{
			canvas = picture.beginRecording(width, height);
		}
		paint.setAntiAlias(true);
		paint.setStyle(Style.FILL);
		paint.setColor(Color.parseColor(backgroundColor));
		canvas.drawRect(0, 0, width, height, paint);

		try
		{
			root.render(canvas);
			//this.drawDemo(canvas);
			// throw new SVGException("render error");
		}
		catch (Exception e)
		{
			paint.setColor(Color.RED);
			paint.setTextSize(20);
			canvas.drawText("程序异常：" + e.getMessage(), 30, 30, paint);
			log.error("程序异常", e);
			e.printStackTrace();
		}
		picture.endRecording();
	}

	public Paint getPaint()
	{
		return paint;
	}

	public RectF getDeviceViewport()
	{
		return deviceViewport;
	}

	public void setDeviceViewport(RectF deviceViewport)
	{
		this.deviceViewport = deviceViewport;
	}

	public SVGElement getElement(String name)
	{
		return (SVGElement) idMap.get(name);
	}

	public void putElement(String name, SVGElement node)
	{
		idMap.put(name, node);
	}

	public void removeElement(String name)
	{
		idMap.remove(name);
	}

	public SVGRoot getRoot()
	{
		return root;
	}

	public void setRoot(SVGRoot root)
	{
		this.root = root;
		root.setDiagram(this);
	}

	public void updateTime(double curTime) throws SVGException
	{
		if (root == null)
			return;
		root.updateTime(curTime);
	}

	private void parse(InputSource inputSource) throws SVGException
	{
		try
		{
			long start = System.currentTimeMillis();
			SVGParser parser = new SVGParser();
			parser.parse(inputSource);
			this.setRoot(parser.getRoot());
			root.build();
			if (log.isDebugEnabled())
			{
				log.debug("idMap " + idMap.size());
			}
			log.warn("parse " + (System.currentTimeMillis() - start) + " ms");
		}
		catch (Exception e)
		{
			throw new SVGException(e);
		}
	}

	@Override
	public void load(byte[] buffer)
	{
		Reader reader = new StringReader(new String(buffer));
		load(reader);
	}

	@Override
	public void load(File file)
	{
		try
		{
			load(new FileInputStream(file));
		}
		catch (FileNotFoundException e)
		{
			log.error(e.getMessage(), e);
		}
	}

	@Override
	public void load(InputStream in)
	{
		Reader reader = new InputStreamReader(in);
		load(reader);
	}

	@Override
	public void load(Reader reader)
	{
		InputSource inputSource = new InputSource(reader);
		try
		{
			parse(inputSource);
		}
		catch (Exception e)
		{
			log.error("load svg final :" + e.getMessage(), e);
		}
	}

	@Override
	public void addMouseListener(SVGMouseListener listener)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void removeMouseListener(SVGMouseListener listener)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public String getAttributeByElementId(String id, String name)
	{
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setAttributeByElementId(String id, String name, String value)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public boolean hasAttributeByElementId(String id, String name)
	{
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void addAttributeByElementId(String id, String name, String value)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void removeAttributeByElementId(String id, String name)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void setScale(double scale)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public double getScale()
	{
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void zoomIn()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void zoomReset()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void zoomOut()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void invalidate()
	{
		repaint();
	}

	@Override
	public void repaint()
	{
		this.render();
	}

	public Drawable getDrawable()
	{
		this.repaint();
		return new PictureDrawable(picture);
	}

	@Override
	public Object getComponent()
	{
		this.repaint();
		return this.picture;
	}

	@Override
	public int getWidth()
	{
		return this.width;
	}

	@Override
	public int getHeight()
	{
		return width;
	}

	@Override
	public SVGElement getSVGElement(String id)
	{
		return idMap.get(id);
	}

	public boolean isDebug()
	{
		return debug;
	}

	public void setDebug(boolean debug)
	{
		this.debug = debug;
	}

	public void drawDemo(Canvas canvas)
	{
		// 创建画笔
		Paint p = new Paint();
		// p.setColor(Color.RED);// 设置红色

		p.setColor(Color.parseColor("#FF3300"));
		canvas.drawText("画圆：", 10, 20, p);// 画文本
		canvas.drawCircle(60, 20, 10, p);// 小圆
		p.setAntiAlias(true);// 设置画笔的锯齿效果。 true是去除，大家一看效果就明白了
		canvas.drawCircle(120, 20, 20, p);// 大圆

		canvas.drawText("画线及弧线：", 10, 60, p);
		p.setColor(Color.GREEN);// 设置绿色
		canvas.drawLine(60, 40, 100, 40, p);// 画线
		canvas.drawLine(110, 40, 190, 80, p);// 斜线
		// 画笑脸弧线
		p.setStyle(Paint.Style.STROKE);// 设置空心
		RectF oval1 = new RectF(150, 20, 180, 40);

		canvas.drawArc(oval1, 180, 180, false, p);// 小弧形
		oval1.set(190, 20, 220, 40);
		canvas.drawArc(oval1, 180, 180, false, p);// 小弧形
		oval1.set(160, 30, 210, 60);
		canvas.drawArc(oval1, 0, 180, false, p);// 小弧形

		canvas.drawText("画矩形：", 10, 80, p);

		p.setColor(Color.GRAY);// 设置灰色
		p.setStyle(Paint.Style.FILL);// 设置填满

		Matrix matrix = new Matrix();
		matrix.setValues(new float[] { 1F, 0F, 0F, 1F, 1F, 13F, 0F, 0F, 1F });
		//matrix.postTranslate(10f,10f);
		//matrix.postConcat(matrix);
		Matrix m = new Matrix();
		m.postConcat(matrix);
		canvas.concat(m);		
		canvas.drawRect(60, 60, 80, 80, p);// 正方形
		canvas.drawRect(60, 90, 160, 100, p);// 长方形
		canvas.restore();
		// 画圆角矩形
		p.setStyle(Paint.Style.FILL);// 充满
		p.setColor(Color.LTGRAY);
		p.setAntiAlias(true);// 设置画笔的锯齿效果
		canvas.drawText("画圆角矩形:", 10, 260, p);
		RectF oval3 = new RectF(80, 260, 200, 300);// 设置个新的长方形
		canvas.drawRoundRect(oval3, 20, 15, p);// 第二个参数是x半径，第三个参数是y半径

		canvas.drawText("画扇形和椭圆:", 10, 120, p);

		Shader mShader = new LinearGradient(0, 0, 100, 100, new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.LTGRAY }, null, Shader.TileMode.REPEAT); // 一个材质,打造出一个线性梯度沿著一条线。
		p.setShader(mShader);

		// p.setColor(Color.BLUE);
		RectF oval2 = new RectF(60, 100, 200, 240);// 设置个新的长方形，扫描测量

		canvas.drawArc(oval2, 200, 130, true, p);
		// 画弧，第一个参数是RectF：该类是第二个参数是角度的开始，第三个参数是多少度，第四个参数是真的时候画扇形，是假的时候画弧线
		// 画椭圆，把oval改一下

		mShader = new LinearGradient(210, 130, 250, 130, new int[] { Color.RED, Color.WHITE, Color.RED }, null, Shader.TileMode.CLAMP); // 一个材质,打造出一个线性梯度沿著一条线。
		p.setShader(mShader);
		oval2.set(210, 100, 250, 130);
		p.setAntiAlias(true);
		canvas.drawOval(oval2, p);

		oval2.set(310, 100, 350, 130);
		// 创建环形渲染对象
		RadialGradient rg = new RadialGradient(330, 115, 20, new int[] { Color.WHITE, Color.RED }, new float[] { 0F, 1F }, Shader.TileMode.CLAMP);
		p.setShader(rg);
		canvas.drawOval(oval2, p);

		canvas.drawText("画三角形：", 10, 200, p);
		// 绘制这个三角形,你可以绘制任意多边形
		Path path = new Path();
		path.moveTo(80, 200);// 此点为多边形的起点
		path.lineTo(120, 250);
		path.lineTo(80, 250);
		path.close(); // 使这些点构成封闭的多边形
		canvas.drawPath(path, p);

		// 你可以绘制很多任意多边形，比如下面画六连形
		p.reset();// 重置
		p.setColor(Color.LTGRAY);
		p.setStyle(Paint.Style.STROKE);// 设置空心
		Path path1 = new Path();
		path1.moveTo(180, 200);
		path1.lineTo(200, 200);
		path1.lineTo(210, 210);
		path1.lineTo(200, 220);
		path1.lineTo(180, 220);
		path1.lineTo(170, 210);
		path1.close();// 封闭
		canvas.drawPath(path1, p);

		// 画贝塞尔曲线
		canvas.drawText("画贝塞尔曲线:", 10, 310, p);
		p.reset();
		p.setStyle(Paint.Style.STROKE);
		p.setColor(Color.GREEN);
		Path path2 = new Path();
		path2.moveTo(100, 320);// 设置Path的起点
		path2.quadTo(150, 310, 170, 400); // 设置贝塞尔曲线的控制点坐标和终点坐标
		canvas.drawPath(path2, p);// 画出贝塞尔曲线

		// 画点
		p.setStyle(Paint.Style.FILL);
		canvas.drawText("画点：", 10, 390, p);
		canvas.drawPoint(60, 390, p);// 画一个点
		canvas.drawPoints(new float[] { 60, 400, 65, 400, 70, 400 }, p);// 画多个点

		// 画图片，就是贴图
		// Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
		// canvas.drawBitmap(bitmap, 250,360, p);

		// LinearGradient(canvas);

	}

	public void drawGradient(Canvas canvas)
	{

		LinearGradient mLinearGradient1 = new LinearGradient(0, 0, 100, 100, new int[] { Color.RED, Color.GREEN }, null, Shader.TileMode.CLAMP);
		LinearGradient mLinearGradient2 = new LinearGradient(0, 0, 0, 100, new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.WHITE }, null, Shader.TileMode.MIRROR);
		LinearGradient mLinearGradient3 = new LinearGradient(0, 0, 0, 100, new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.WHITE }, null, Shader.TileMode.REPEAT);
		Paint mPaint = new Paint();

		Paint paint = new Paint();
		paint.setTextSize(20);
		paint.setColor(Color.WHITE);
		// 绘制渐变的矩形
		mPaint.setShader(mLinearGradient1);
		canvas.drawRect(0, 0, 200, 200, mPaint);
		canvas.drawText("CLAMP", 0, 200 + 20, paint);
		// 绘制渐变的矩形
		mPaint.setShader(mLinearGradient2);
		canvas.drawRect(0, 250, 200, 450, mPaint);
		canvas.drawText("MIRROR", 0, 450 + 20, paint);
		// 绘制渐变的矩形
		mPaint.setShader(mLinearGradient3);
		canvas.drawRect(0, 500, 200, 700, mPaint);
		canvas.drawText("REPEAT", 0, 700 + 20, paint);
	}
}
